﻿using System;
using System.IO;
using System.Web;
using System.Web.Script.Serialization;
using System.Xml;
using Desjardins.Transaction;
using Medianamik.Core;
using Medianamik.Core.Logging;
using Medianamik.UI.Web.MVP.Presentation;
using Medianamik.UI.Web.Shop.Services;

namespace Medianamik.UI.Web.Shop.Presentation.Presenters
{
    public class DesjardinsEndPresenter<T, TOrder, TOrderItem, TShoppingCart, TShoppingCartItem,
            TProduct, TModel, TShoppingCartItemWithModels> : ModulePresenter<T>
        where T : IDesjardinsView
        where TOrder : Data.Interfaces.IOrder<TOrderItem>
        where TOrderItem : Data.Interfaces.IOrderItem
        where TShoppingCart : Data.Interfaces.IShoppingCart<TShoppingCartItem, TModel>
        where TProduct : Data.Interfaces.IProduct
        where TModel : Data.Interfaces.IModel
        where TShoppingCartItem : Data.Interfaces.IShoppingCartItem<TModel>
    {
        public static readonly ILogger Logger = new ObjectFactory<ILogger>().Get("ShopLogger");
        private readonly JavaScriptSerializer _serializer; 
        private readonly IOrderService<TOrder, TOrderItem, TShoppingCart, TShoppingCartItem,
            TProduct, TModel, TShoppingCartItemWithModels> _orderService;

        private string _responseToPaymentServer;

        public DesjardinsEndPresenter(T view, IOrderService<TOrder, TOrderItem, TShoppingCart, TShoppingCartItem,
            TProduct, TModel, TShoppingCartItemWithModels> orderService)
            : base(view)
        {
            _orderService = orderService;
            _serializer = new JavaScriptSerializer();

        }

        protected virtual string XMLReceiptPath { get { return "/Desjardins/"; } }

        protected XmlDocument GetXMLDocument(string xmlData)
        {
            var xmlDocument = new XmlDocument(); ;

            try
            {
                xmlDocument.LoadXml(xmlData);
            }
            catch (Exception e)
            {
                xmlDocument = null;
                Logger.Trace(e.Message);
            }

            return xmlDocument;
        }

        protected override void Initialize(object sender, System.EventArgs e)
        {
            base.Initialize(sender, e);
            try
            {
                _responseToPaymentServer = string.Empty;

                var desjardinsResponse = Purchase.GetDesjardinsResponse(View); 

                if (desjardinsResponse != null)
                {
                    if (IsXMLResponse(desjardinsResponse))
                    {
                        var xmlDocument = GetXMLDocument(desjardinsResponse);

                        if (xmlDocument != null)
                        {
                            _responseToPaymentServer = !IsConfirm(desjardinsResponse) ?
                                AskConfirmation(desjardinsResponse) : FinalConfirmation(desjardinsResponse);
                        }else
                        {
                            _responseToPaymentServer = Purchase.ErrorConfirmation();
                        }
                    }
                }
                else
                {
                    _responseToPaymentServer = Purchase.ErrorConfirmation();
                }
            }
            catch (Exception exception)
            {
                Logger.Trace(exception.Message);
                _responseToPaymentServer = Purchase.ErrorConfirmation();
            }

            View.OverriddenRender += View_OverriddenRender;
        }

        void View_OverriddenRender(object sender, MVP.View.RenderEventArgs e)
        {
            Logger.Trace(_responseToPaymentServer);
            e.Writer.Write(_responseToPaymentServer);
        }

        protected virtual string AskConfirmation(string xmlData)
        {
            string askConfirmation;

            var responseXML = new XmlDocument();
            responseXML.LoadXml(xmlData);

            var responseResult = new PurchaseResult(xmlData);

            Logger.Trace(responseResult.ServerResponse);

            if (GetCurrentOrder(responseResult.TransactionId).PaymentData.IsNullOrEmpty())
            {
                
                if (responseResult.Approved)
                {
                    if (SaveConfirmationXML(responseXML, responseResult.TransactionId, XMLReceiptPath))
                    {
                        askConfirmation = Purchase.AskConfirmation(responseResult);
                    }
                    else
                    {
                        askConfirmation = Purchase.ErrorConfirmation();
                    }
                }
                else
                {
                    askConfirmation = Purchase.ErrorConfirmation();
                }
            }
            else
            {
                Logger.Trace("The payment is already completed for this transaction." + responseResult.TransactionId);
                askConfirmation = Purchase.ErrorConfirmation();
            }

            return askConfirmation;
        }

        protected virtual string FinalConfirmation(string xmlData)
        {
            var responseXML = new XmlDocument();
            responseXML.LoadXml(xmlData);
           
            var responseResult = new ConfirmationResult(xmlData);
            Logger.Trace(responseResult.ServerResponse);

            string finalConfirmation;

            if(SavePaymentDataInOrder(responseResult.PaymentProviderTransactionKey, XMLReceiptPath))
            {
                finalConfirmation = Purchase.FinalConfirmation(responseResult,true);
                DeleteShoppingCart(responseResult.PaymentProviderTransactionKey);
                DeleteCookie();
            }
            else
            {
                finalConfirmation = Purchase.ErrorConfirmation();
            }

           return finalConfirmation;
        }

        protected virtual void DeleteShoppingCart(string transactionId)
        {
            var orderId = GetCurrentOrder(transactionId).NodeId;
            _orderService.ShoppingCartService.DeleteShoppingCart(_orderService.ShoppingCartService.GetShoppingCartByOrderId(orderId).NodeId);
        }

        private TOrder _currentOrder;
        private TOrder GetCurrentOrder(string transactionId)
        {
            if (_currentOrder == null)
            {
                _currentOrder = _orderService.GetOrderByTransactionId(transactionId);
            }

            return _currentOrder;
        }

        protected virtual bool SavePaymentDataInOrder(string transactionId, string receiptPath)
        {
            var saved = false;

            try
            {
                var paymentData = File.OpenText(HttpContext.Current.Server.MapPath(receiptPath) + transactionId + ".xml").ReadToEnd();
                var currentOrder = GetCurrentOrder(transactionId);

                currentOrder.PaymentData = paymentData;
                _orderService.SaveOrder(currentOrder);
                saved = true;
            }
            catch (Exception exception)
            {
                Logger.Trace(exception.Message);
            }

            return saved;
        }

        protected virtual void DeleteCookie()
        {
            var cookie = new HttpCookie(Constants.ShoppingCartCookieName) {Expires = DateTime.Now.AddDays(-1)};
            HttpContext.Current.Response.Cookies.Add(cookie);
        }

        protected virtual bool SaveConfirmationXML(XmlDocument xmlDocument , 
            string transactionId, string receiptPath)
        {
            bool confirmed = true;

            try
            {
                xmlDocument.Save(HttpContext.Current.Server.MapPath(receiptPath) + transactionId + ".xml");
            }
            catch(Exception exception)
            {
                confirmed = false;
                Logger.Trace(exception.Message);
            }

            return confirmed;
        }

        protected virtual bool IsXMLResponse(string textResponse)
        {
            return textResponse.IndexOf("<request input=\"xml\">") > 0;
        }

        protected virtual bool IsConfirm(string textResponse)
        {
            return textResponse.IndexOf("<confirm>") > 0;
        }    
    }
}
